package jwlee.testnetwork;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class ChatServer {
	private static final int SERVER_PORT = 30000;

	// 使用MyMap对象来保存每个客户名字和对应输出流之间的对应关系。
	public static ChatMap<String, PrintStream> clients = new ChatMap<String, PrintStream>();

	// 定义保存所有Socket的List
	public static List<Socket> socketList = new ArrayList<Socket>();

	private void start() throws IOException {
		ServerSocket ss = null;

		try {
			// 建立监听的ServerSocket
			ss = new ServerSocket(SERVER_PORT);
			// 采用死循环来不断接受来自客户端的请求
			while (true) {
				Socket socket = ss.accept();
				new Thread(new ChatServerThread(socket)).start();
			}
		} catch (IOException ex) {
			System.out.println("服务器启动失败，是否端口" + SERVER_PORT + "已被占用？");
		} finally {
			try {
				if (ss != null) {
					ss.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
			System.exit(1);
		}
	}

	public static void main(String[] args) throws IOException {
		new ChatServer().start();
	}

	// 负责处理每个线程通信的线程类
	class ChatServerThread implements Runnable {
		private Socket socket;

		BufferedReader br = null;

		PrintStream ps = null;

		// 定义一个构造器，用于接收一个Socket来创建ServerThread线程
		public ChatServerThread(Socket socket) {
			this.socket = socket;
		}

		public void run() {
			try {
				// 获取该Socket对应的输入流

				br = new BufferedReader(new InputStreamReader(socket
						.getInputStream()));

				// 获取该Socket对应的输出流

				ps = new PrintStream(socket.getOutputStream());

				String line = null;

				while ((line = br.readLine()) != null)

				{

					// 如果读到的行以MyProtocol.USER_ROUND开始，并以其结束，

					// 可以确定读到的是用户登录的用户名

					if (line.startsWith(ChatProtocol.USER_ROUND)
							&& line.endsWith(ChatProtocol.USER_ROUND)) {
						// 得到真实消息
						String userName = getRealMsg(line);
						// 如果用户名重复
						if (ChatServer.clients.containsKey(userName)) {
							System.out.println("重复");
							ps.println(ChatProtocol.NAME_REP);
						} else {
							System.out.println("成功");
							ps.println(ChatProtocol.LOGIN_SUCCESS);
							ChatServer.clients.put(userName, ps);
						}
					}

					// 如果读到的行以YeekuProtocol.PRIVATE_ROUND开始，并以其结束，
					// 可以确定是私聊信息，私聊信息只向特定的输出流发送
					else if (line.startsWith(ChatProtocol.PRIVATE_ROUND)
							&& line.endsWith(ChatProtocol.PRIVATE_ROUND)) {
						// 得到真实消息
						String userAndMsg = getRealMsg(line);
						// 以SPLIT_SIGN来分割字符串，前面部分是私聊用户，后面部分是聊天信息
						String user = userAndMsg.split(ChatProtocol.SPLIT_SIGN)[0];
						String msg = userAndMsg.split(ChatProtocol.SPLIT_SIGN)[1];
						// 获取私聊用户对应的输出流，并发送私聊信息
						ChatServer.clients.get(user).println(
								ChatServer.clients.getKeyByValue(ps)
										+ "悄悄地对你说：" + msg);
					}
					// 公聊要向每个Socket发送
					else {
						// 得到真实消息
						String msg = getRealMsg(line);
						// 遍历clients中的每个输出流
						for (PrintStream clientPs : ChatServer.clients
								.valueSet()) {
							clientPs.println(ChatServer.clients
									.getKeyByValue(ps)

									+ "说：" + msg);

						}
					}

				}

			}

			// 捕捉到异常后，表明该Socket对应的客户端已经出现了问题

			// 所以程序将其对应的输出流从Map中删除

			catch (IOException e) {
				ChatServer.clients.removeByValue(ps);

				System.out.println(ChatServer.clients.size());

				// 关闭网络、IO资源

				try

				{

					if (br != null)

					{

						br.close();

					}

					if (ps != null)

					{

						ps.close();

					}

					if (socket != null)

					{

						socket.close();

					}

				}

				catch (IOException ex)

				{

					ex.printStackTrace();

				}

			}

		}

		// 将读到的内容去掉前后的协议字符，恢复成真实数据

		public String getRealMsg(String line)

		{

			return line.substring(ChatProtocol.PROTOCOL_LEN,

			line.length() - ChatProtocol.PROTOCOL_LEN);

		}
	}

}
